package com.atguigu.gmall.order.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.cart.CartFeign;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.enums.OrderStatus;
import com.atguigu.gmall.model.enums.ProcessStatus;
import com.atguigu.gmall.model.order.OrderDetail;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.order.mapper.OrderDetailMapper;
import com.atguigu.gmall.order.mapper.OrderInfoMapper;
import com.atguigu.gmall.order.service.OrderInfoService;
import com.atguigu.gmall.order.util.OrderThreadLocalUtil;
import com.atguigu.gmall.product.ProductFeign;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.log4j.Log4j2;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

@Service
@Log4j2
@Transactional(rollbackFor = Exception.class)
public class OrderInfoServiceImpl implements OrderInfoService {
    @Autowired
    CartFeign cartFeign;
    @Autowired
    ProductFeign productFeign;
    @Autowired
    RedisTemplate redisTemplate;
    @Resource
    OrderInfoMapper orderInfoMapper;
    @Autowired
    RabbitTemplate rabbitTemplate;
    /**
     * 新增订单
     *
     * @param orderInfo
     */
    @Override
    public void addOrderInfo(OrderInfo orderInfo) {
        //参数校验
        if (orderInfo == null ){
            return;
        }
        //利用redis的原子性控制重复下单问题
        Long increment =
                redisTemplate.opsForValue().increment("User_Order_Account" + OrderThreadLocalUtil.get(), 1);
        if (increment > 1){
            throw new RuntimeException("新增订单失败，用户已经提交过相同订单！！！");
        }try {
            //第一次下单，为了防止死锁设置过期时间 使用expire方法
            redisTemplate.expire("User_Order_Account"+OrderThreadLocalUtil.get(),10,TimeUnit.SECONDS);
            //补全订单信息
            //调用购物车微服务获得相关数据
            Map<String, Object> orderCart = cartFeign.getOrderCart();
            //判断当前用户购物车是否有选中商品
            if (orderCart == null || orderCart.isEmpty()){
                throw new RuntimeException("购物车中没有数据，新增失败");
            }
            orderInfo.setTotalAmount(new BigDecimal(orderCart.get("totalPrice").toString()));
            orderInfo.setOrderStatus(OrderStatus.UNPAID.getComment());
            orderInfo.setUserId(OrderThreadLocalUtil.get());
            orderInfo.setProcessStatus(ProcessStatus.UNPAID.getComment());
            orderInfo.setExpireTime(new Date(System.currentTimeMillis()+1800000));
            orderInfo.setCreateTime(new Date());
            //将数据存到数据库
            int insert = orderInfoMapper.insert(orderInfo);
            if (insert <= 0 ){
                throw new RuntimeException("新增订单失败");
            }
            //获取订单Id
            Long orderId = orderInfo.getId();
            //根据订单ID查询当笔订单所有购买的商品
            List cartInfoList = (List) orderCart.get("cartInfoList");
            //订单明细保存 并返回销售的商品的id和销售出去的数量
            Map<String, String> detailMap = addOrderDetail(orderId, cartInfoList);
            //清空购物车
           //一直删除数据太麻烦先注释
           cartFeign.clearCart();
            //扣减库存
            productFeign.deductSku(detailMap);
            //生成订单30分钟后用户未下单使用定时任务判断用户超时取消订单
            rabbitTemplate.convertAndSend(
                    "order_nomal_exchange",
                    "order.nomal",
                    orderId+"",
                    (message -> {
                        //获取消息的属性
                        MessageProperties messageProperties = message.getMessageProperties();
                        //设置消息的过期时间: 毫秒
                        messageProperties.setExpiration("30000");
                        //返回
                        return message;
                    }));
        }catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }finally {
            redisTemplate.delete("User_Order_Account"+OrderThreadLocalUtil.get());
        }
    }
    @Resource
    private OrderDetailMapper orderDetailMapper;
    /**
     * 将每笔点单的所有数据保存到订单详情表
     * @param orderId
     * @param cartInfoList
     * @return
     */
    private Map<String, String> addOrderDetail(Long orderId, List cartInfoList) {
        Map<String,String> detailMap = new ConcurrentHashMap<>();
        cartInfoList.stream().forEach(o -> {
            //将Object 序列化
            String json = JSONObject.toJSONString(o);
            //反序列化
            CartInfo cartInfo = JSONObject.parseObject(json, CartInfo.class);
            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setOrderId(orderId);
            orderDetail.setSkuId(cartInfo.getSkuId());
            orderDetail.setSkuName(cartInfo.getSkuName());
            orderDetail.setImgUrl(cartInfo.getImgUrl());
            orderDetail.setOrderPrice(cartInfo.getSkuPrice());
            orderDetail.setSkuNum(cartInfo.getSkuNum());
            int insert = orderDetailMapper.insert(orderDetail);
            if (insert <= 0){
                throw new RuntimeException("新增订单详情失败！！！！");
            }
            //返回销售商品的id和对应的数量
            detailMap.put(cartInfo.getSkuId()+"",cartInfo.getSkuNum()+"");
        });
        return detailMap;
    }

    /**
     * 取消订单 用户主动 / 超时取消
     *
     * @param orderId
     */
    @Override
    public void cancelOrder(Long orderId) {
        //参数校验
        if (orderId == null){
            return;
        }
        //以下操作存在同步问题，需要进行幂等性校验
        Long i = redisTemplate.opsForValue()
                .increment("User_Order_Cancel_Count_" + orderId, 1);
        if (i > 1){
            //说明不是第一次操作 应该拒绝请求
            throw new RuntimeException("取消订单失败，用户重复取消订单！！！");
        }try {
            //防止锁一直存在，用户一直不能取消当前订单
            redisTemplate.expire("User_Order_Cancel_Count_" + orderId,10,TimeUnit.SECONDS);
            //获取用户名根据用户名是否为空判断是超时取消还是主动取消
            String username = OrderThreadLocalUtil.get();
            //声明标志条件用于判断账单状态
            boolean flag = true; //为true时表示状态为超时取消
            //初始化查询条件
            LambdaQueryWrapper<OrderInfo> wrapper
                    = new LambdaQueryWrapper<>();
            //构造查询条件
            wrapper.eq(OrderInfo::getId,orderId).
                    eq(OrderInfo::getOrderStatus,OrderStatus.UNPAID.getComment());
            //如果用户id不为空说明是用户主动取消订单
            if (!StringUtils.isEmpty(username)){
                flag = false;
                wrapper.eq(OrderInfo::getUserId,username);
            }
            //根据订单ID和订单状态为未支付的状态查询相关订单
            OrderInfo orderInfo = orderInfoMapper.selectOne(wrapper);
            if (orderInfo == null || orderInfo.getId() == null){
                //说明未查询到订单，直接返回
                return;
            }
            //修改订单状态
            if (flag){
                orderInfo.setOrderStatus(OrderStatus.TIMEOUT.getComment());
                orderInfo.setProcessStatus(ProcessStatus.TIMEOUT.getComment());
            }else {
                orderInfo.setOrderStatus(OrderStatus.CANCEL.getComment());
                orderInfo.setProcessStatus(ProcessStatus.CANCEL.getComment());
            }
            //修改数据库
            int update = orderInfoMapper.updateById(orderInfo);
            if (update < 0 ){
                log.error("取消订单失败，订单Id为："+orderId);
                throw new RuntimeException("取消订单失败，请重试！！！");
            }
            rollBackStock(orderId);
        }catch (Exception e){
            e.printStackTrace();
            throw  new RuntimeException("用户取消订单失败，订单ID 为"+orderId);
        }finally {
            //防止锁一直存在，用户一直不能取消当前订单
            redisTemplate.delete("User_Order_Cancel_Count_" + orderId);
        }

    }

    /**
     * 查询购物车详情表根据取消订单回滚对应的库存
     * @param orderId
     */
    private void rollBackStock(Long orderId) {
        Map<String,String> rollbackMap = new ConcurrentHashMap<>();
        //根据订单id查询取消订单的数量和对应的商品id
        List<OrderDetail> orderDetails =
                orderDetailMapper.selectList(
                        new LambdaQueryWrapper<OrderDetail>().
                                eq(OrderDetail::getOrderId, orderId));

        orderDetails.stream().forEach(orderDetail -> {
            Long skuId = orderDetail.getSkuId();
            Integer skuNum = orderDetail.getSkuNum();
            if (skuId !=0 && skuNum != 0) {
                rollbackMap.put("skuId", skuId + "");
                rollbackMap.put("skuNum", skuNum + "");
            }
        });
        //调用商品微服务回滚库存
        productFeign.rollBackStock(rollbackMap);
    }
}
